package com.nbstar.film.spider.font.woff;

import com.nbstar.film.spider.font.woff.table.*;
import com.nbstar.film.spider.font.woff.table.glyf.GlyphTable;
import com.nbstar.film.spider.font.woff.table.gsub.GlyphSubstitutionTable;
import com.nbstar.film.spider.font.woff.table.name.NamingTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @Description: 功能描述：parse woff file
 * @ClassName: WoffParse
 * @author: Wang Xindong
 * @date: 2018年8月30日 上午9:40:51
 * @email: wangxindong@travelsky.com
 * @Copyright: Copyright (c) 2018. All rights reserved.
 */
public class WoffParse {

    private static final Logger LOGGER = LoggerFactory.getLogger(WoffParse.class);

    private static final Pattern FILE_PATTERN = Pattern.compile(".woff|WOFF");

    public WoffParse() {
    }

    private void checkFile(String fileName) {
        Matcher matcher = FILE_PATTERN.matcher(fileName);
        if (!matcher.find()) {
            throw new RuntimeException("file is not validate woff file");
        }
    }

    public WoffFont parse(String ttfFile) throws IOException {
        checkFile(ttfFile);
        return parse(new File(ttfFile));
    }

    public WoffFont parse(InputStream input) throws IOException {
        AbstractOTFDataStream stream = new ByteBufferOTFDataStream(input);
        return parse(stream);
    }

    public WoffFont parse(File file) throws IOException {
        checkFile(file.getName());
        InputStream fileStream = new FileInputStream(file);
        return parse(fileStream);
    }

    public WoffFont parse(AbstractOTFDataStream stream) throws IOException {
        WoffFont font = newWoffFont(stream);
        font.parseWoffFontHeader(stream);

        // WOFF TableDirectoryEntry
        int numTables = font.getHeader().getNumTables();
        for (int i = 0; i < numTables; i++) {
            AbstractWoffTable table = readTableDirectory(font, stream);
            if (null != table) {
                font.addTable(table);
            }
        }
        // parse table
        parseTables(font);
        return font;
    }

    private void parseTables(WoffFont font) throws IOException {
        for (AbstractWoffTable table : font.getTables()) {
            font.readTable(table);
        }
    }

    /**
     * 读取表
     *
     * @param font
     * @param stream
     * @return
     */
    private AbstractWoffTable readTableDirectory(WoffFont font, AbstractOTFDataStream stream) throws IOException {
        AbstractWoffTable table = null;
        String tag = stream.readString(4);
        if (tag.equalsIgnoreCase(CmapTable.TAG)) {
            table = new CmapTable(font);
        } else if (tag.equalsIgnoreCase(MaximumProfileTable.TAG)) {
            table = new MaximumProfileTable(font);
        } else if (tag.equalsIgnoreCase(GlyphSubstitutionTable.TAG)) {
            table = new GlyphSubstitutionTable(font);
        } else if (tag.equalsIgnoreCase(OS2WindowsMetricsTable.TAG)) {
            table = new OS2WindowsMetricsTable(font);
        } else if (tag.equalsIgnoreCase(HeaderTable.TAG)) {
            table = new HeaderTable(font);
        } else if (tag.equalsIgnoreCase(HorizontalHeaderTable.TAG)) {
            table = new HorizontalHeaderTable(font);
        } else if (tag.equalsIgnoreCase(IndexToLocationTable.TAG)) {
            table = new IndexToLocationTable(font);
        } else if (tag.equalsIgnoreCase(NamingTable.TAG)) {
            table = new NamingTable(font);
        } else if (tag.equalsIgnoreCase(PostScriptTable.TAG)) {
            table = new PostScriptTable(font);
        } else if (tag.equalsIgnoreCase(HorizontalMetricsTable.TAG)) {
            table = new HorizontalMetricsTable(font);
        } else if (tag.equalsIgnoreCase(GlyphTable.TAG)) {
            table = new GlyphTable(font);
        } else {
            // unknow table
            table = new EntityWoffTable(font);
        }

        table.setTag(tag);
        table.setOffset(stream.readInt());
        table.setCompLength(stream.readInt());
        table.setOrigLength(stream.readInt());
        table.setOrigChecksum(stream.readInt());
        return table;
    }


    private WoffFont newWoffFont(AbstractOTFDataStream stream) throws IOException {
        return new WoffFont(stream);
    }


}
